package com.supreme.simpleserver.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.SourceLocation;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * 定义Aspect切面拦截controller
 */
@Aspect
//@Component
@Slf4j
public class ControllerAspect {

    @Pointcut(value = "execution(public * com.supreme..controller..*.*(..))")
    public void PointCut() {
    }

    /**
     * step1
     * proceedingJoinPoint.proceed() 之前调用: 请求之前处理
     * proceedingJoinPoint.proceed() 之后调用: 请求之后处理
     * proceedingJoinPoint.proceed()异常通过声明抛出: 框架处理/全局异常处理
     *
     * 以下自定义处理异常
     * try {
     *     object = proceedingJoinPoint.proceed();
     * } catch (Throwable throwable) {
     *     throwable.printStackTrace();
     * }
     *
     * @param proceedingJoinPoint proceedingJoinPoint
     * @return Object
     */
    @Around("PointCut()")
    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Signature signature = proceedingJoinPoint.getSignature();
        log.info("aroundMethod start: {}", signature.toShortString());

        Object object = proceedingJoinPoint.proceed();

        log.info("aroundMethod finish: {}", object.toString());
        return object;
    }

    private void processJoinPoint(JoinPoint joinPoint) {
        //获取目标方法参数信息
        Object[] joinPointArgs = joinPoint.getArgs();
        Arrays.stream(joinPointArgs).forEach(arg -> {
            System.out.println(arg.toString());
        });

        //aop代理对象
        Object joinPointThis = joinPoint.getThis();
        log.info("joinPointThis: {}", joinPointThis.toString());

        //被代理对象
        Object joinPointTarget = joinPoint.getTarget();
        log.info("joinPointTarget: {}", joinPointTarget.toString());

        //获取连接点的方法签名对象
        Signature joinPointSignature = joinPoint.getSignature();
        System.out.println("joinPointSignature toLongString: " + joinPointSignature.toLongString());
        System.out.println("joinPointSignature toShortString: " + joinPointSignature.toShortString());
        System.out.println("joinPointSignature toString: " + joinPointSignature.toString());
        System.out.println("joinPointSignature getDeclaringTypeName: " + joinPointSignature.getDeclaringTypeName());
        System.out.println("joinPointSignature getDeclaringType toString" + joinPointSignature.getDeclaringType().toString());
        System.out.println("joinPointSignature getDeclaringType getName: " + joinPointSignature.getDeclaringType().getName());

        //连接点类型
        String joinPointKind = joinPoint.getKind();
        log.info("joinPointKind: " + joinPointKind);

        //返回连接点方法所在类文件中的位置  打印报异常
        SourceLocation joinPointSourceLocation = joinPoint.getSourceLocation();
        log.info("joinPointSourceLocation: " + joinPointSourceLocation.toString());

        ///返回连接点静态部分
        JoinPoint.StaticPart joinPointStaticPart = joinPoint.getStaticPart();
        log.info("joinPointStaticPart: " + joinPointStaticPart.toString());
    }

    /**
     * step2
     * @param joinPoint
     */
    @Before("PointCut()")
    public void beforeMethod(JoinPoint joinPoint) {
        log.info("beforeMethod: {}", joinPoint.getKind());

//        processJoinPoint(joinPoint);

        ServletRequestAttributes attributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            String requestURI = request.getRequestURI();
            StringBuffer requestURL = request.getRequestURL();
            String requestMethod = request.getMethod();
            log.info("requestURI: {} requestURL: {} requestMethod: {}", requestURI, requestURL, requestMethod);
        }
    }

    /**
     * step3
     * @param joinPoint
     * @param result
     */
    @AfterReturning(value = "PointCut()", returning = "result")
    public void afterReturningMethod(JoinPoint joinPoint, Object result) {
        log.info("afterReturningMethod: " + result.toString());
    }

    /**
     * step4
     * @param joinPoint
     */
    @After("PointCut()")
    public void afterMethod(JoinPoint joinPoint) {
        log.info("afterMethod");
    }

    @AfterThrowing(value = "PointCut()", throwing = "exception")
    public void afterPointCutMethod(JoinPoint joinPoint, Exception exception) {
        log.info("afterPointCutMethod");
    }
}
